/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package infoplaces2;

import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import javax.imageio.ImageIO;

/**
 *
 * @author Andre Alvarado
 */
public class GoogleStreetMap extends StreetMap<EquirectangularPanoramicImage, String>{
    
    private final HashMap<String, GoogleStreetNode> nodes = new HashMap<>();

    public HashMap<String, GoogleStreetNode> getNodes() {
        return nodes;
    }
    
    
    @Override
    public GoogleStreetNode addNode(double latitude, double longitude) {
        try {
            String myXML = getContentOfURL("http://cbk0.google.com/cbk?output=xml&ll=" + latitude + "," + longitude);
            String panoID = getXMLPanoID(myXML);
            return this.addNode(panoID);
        }
        catch (IOException error) {
            throw new GoogleStreetMapException(error);
        }
    }
    
    @Override
    public GoogleStreetNode addNode(String panoID) {
        GoogleStreetNode node = this.nodes.get(panoID);
        if (node != null) {
            return node;
        }
        
        try {
            //preciso de PanoramicImage e de um pano_id
            String myXML = getContentOfURL("http://cbk0.google.com/cbk?output=xml&panoid=" + panoID);

            double latitude = getXMLLatitude(myXML);
            double longitude = getXMLLongitude(myXML);
            double north = getXMLNorte(myXML);
            ArrayList<String> neighbours = getXMLVizinhos(myXML);

            //criar uma EquirectangularPanoramicImage e no seu construtor fazer td q for necessario para criar de fato uma EquirectangularPanoramicImage

            ArrayList<BufferedImage> images = new ArrayList<>();
            for (int i = 0; i < 4; i++) {
                for (int j = 0; j < 2; j++) {
                    images.add(ImageIO.read(new URL("http://cbk0.google.com/cbk?output=tile&panoid=" + panoID + "&zoom=2&x=" + i + "&y=" + j)));
                }
            }

            BufferedImage equirectangular = juntarImagensArrayList(images); //junta essas imagens da lista em uma só imagem em formato de BufferedImage
            EquirectangularPanoramicImage equirectangularPanoramicImage = new EquirectangularPanoramicImage(equirectangular); //cria um EquirectangularPanoramicImage a partir desse BufferedImage

            ImageIO.write(equirectangular, "png", new File("equirectangular.png")); // salvando a imagem Equirectangular APENAS PARA TESTE. APAGAR DEPOIS.

            node = new GoogleStreetNode(latitude, longitude, equirectangularPanoramicImage, panoID, neighbours, north);
            this.nodes.put(panoID, node);

            return node;
        }
        catch (IOException error) {
            throw new GoogleStreetMapException(error);
        }
    }
    
    private static BufferedImage juntarImagensArrayList(ArrayList<BufferedImage> images) {

        //Largura e Altura de uma imagem
        int width = images.get(0).getWidth();
        int height = images.get(0).getWidth();

        BufferedImage dest = new BufferedImage(width * 4, height * 2, BufferedImage.TYPE_INT_ARGB);

        //Obtemos o contexto gráfico da imagem final.
        Graphics2D g2d = dest.createGraphics();
        
        try {
            //Desenhamos a primeira linha de imagens
            g2d.drawImage(images.get(0), 0, 0, null);
            g2d.drawImage(images.get(2), width, 0, null);
            g2d.drawImage(images.get(4), width * 2, 0, null);
            g2d.drawImage(images.get(6), width * 3, 0, null);

            //Desenhamos a segunda linha de imagens
            g2d.drawImage(images.get(1), 0, height, null);
            g2d.drawImage(images.get(3), width, height, null);
            g2d.drawImage(images.get(5), width * 2, height, null);
            g2d.drawImage(images.get(7), width * 3, height, null);
        }
        finally {
            //Descartamos o contexto gráfico  
            g2d.dispose();
        }

        //Salvamos a imagem final no disco.  
        //ImageIO.write(dest, "png", new File("panorama_com_repeticao.png"));

        return dest.getSubimage(0, 0, 1665, 832); // Corta a repetição
    }
    
    public static String getContentOfURL(String path) throws IOException {
        String input;
        URL url = new URL(path);

        try (BufferedReader br = new BufferedReader(new InputStreamReader(url.openConnection().getInputStream()))) {
            input = br.readLine();
        }

        return input;
    }

    public static String getXMLPanoID(String xml) {
        String pano_id = "pano_id=";
        String fim = " imagery_type";

        int indexInicial = xml.indexOf(pano_id) + pano_id.length() + 1;
        int indexFinal = xml.indexOf(fim) - 1;

        return xml.substring(indexInicial, indexFinal);
    }

    private static ArrayList<String> getXMLVizinhos(String xml) {
        ArrayList<String> vizinhos = new ArrayList<>();

        String annotation_properties = getXMLAnnotatioProprieties(xml);

        //Link

        //Inicio
        String inicioLink = "<link";
        int indexInicialLink = annotation_properties.indexOf(inicioLink);

        //Fim
        String finalLink = "</link>";
        int indexFinalLink = annotation_properties.indexOf(finalLink) + finalLink.length();

        int finalAnnotation = annotation_properties.indexOf("</annotation_properties>");

        String inicioPanoId = "pano_id=";
        String fimPanoId = " road_argb";

        String vizinho;
        String link;

        while ((indexInicialLink) <= finalAnnotation) {
            link = annotation_properties.substring(indexInicialLink, indexFinalLink);

            vizinho = link.substring(link.indexOf(inicioPanoId) + inicioPanoId.length() + 1, link.indexOf(fimPanoId) - 1);

            vizinhos.add(vizinho);

            indexInicialLink = indexFinalLink + 1;
            indexFinalLink = annotation_properties.indexOf(finalLink, indexInicialLink) + finalLink.length();
        }

        //System.out.println("Vizinho 1 = " + vizinhos.get(0));
        //System.out.println("Vizinho 2 = " + vizinhos.get(1));

        return vizinhos;

    }

    private static String getXMLAnnotatioProprieties(String xml_archive) {

        //Inicio
        String inicioAnnotationProperties = "<annotation_properties>";
        int indexInicialAnnotations = xml_archive.indexOf(inicioAnnotationProperties);

        //Fim
        String finalAnnotationProperties = "</annotation_properties>";
        int indexFinalAnnotations = xml_archive.indexOf(finalAnnotationProperties) + finalAnnotationProperties.length();

        //annotation_properties
        String annotation_properties = xml_archive.substring(indexInicialAnnotations, indexFinalAnnotations);

        //System.out.println(annotation_properties);

        return annotation_properties;
    }

    private static double getXMLNorte(String myXML) {
        String yaw = "pano_yaw_deg=";
        String fimYaw = " tilt_yaw_deg";
        
        String yawValue = getXMLElement(myXML, yaw, fimYaw);

       return Double.parseDouble(yawValue);

    }

    public static double getXMLLatitude(String myXML) {
        String latitude = getXMLElement(myXML, "lat=", " lng");
        return Double.parseDouble(latitude);
    }

    public static double getXMLLongitude(String myXML) {
        String longitude = getXMLElement(myXML, "lng=", " original_lat=");
        return Double.parseDouble(longitude);

    }
    
    private static String getXMLElement(String myXML, String condicaoInicial, String condicaoFinal) {
        int indexCondicaoInicial = myXML.indexOf(condicaoInicial) + condicaoInicial.length() + 1;
        int indexCondicaoFinal = myXML.indexOf(condicaoFinal) - 1;

        return myXML.substring(indexCondicaoInicial, indexCondicaoFinal);
    }

}
